
# coding: utf-8

# In[1]:

#!usr/bin/python3

print("你好,欢迎学习相关关系的挖掘算法-Apriori算法,也称先验算法.")
print("使用Apriori算法进行关联分析")
print('关联分析是一种在大规模数据集中寻找有趣关系的任务,包括频繁项集或关联规则.')


# In[18]:

#  首先，使用Apriori算法发现频繁项集
# 下面创建一个用于构建初始集合的函数和一个通过扫面数据集以寻找交易记录子集的函数
def loadDataSet():
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]
def createC1(dataset):  # 构建第一个候选项集的列表C1
    C1=[]   # 用来存储不重复的项值
    for transaction in dataSet:
        for item in transaction:
            if [item] not in C1:
                C1.append([item])  # 这里添加只包含该物品项的一个列表,注意Python不能创建只有一个整数的集合，因此这里使用列表形式
    C1.sort()
    return list(map(frozenset,C1))  # 对C1中每个项构建一个不变集合,frozenset是不可变集合
def scanD(D,Ck,minSupport):      # 该函数用于从C1生成L1
    ssCnt={}
    for tid in D:
        for can in Ck:  # 遍历C1中的所有候选集
            if can.issubset(tid):
                if can not in ssCnt:
                    ssCnt[can]=1
                else:
                    ssCnt[can]+=1
    numItems=float(len(D))
    retList=[]  # 包含满足最小支持度要求的集合
    supportData={}
    for key in ssCnt:
        support=ssCnt[key]/numItems
        if support>=minSupport:
            retList.insert(0,key)
        supportData[key]=support
    return retList,supportData


# In[19]:

dataSet=loadDataSet()
dataSet


# In[4]:

C1=createC1(dataSet)
C1


# In[20]:

D=list(map(set,dataSet))  # 构建集合表示的数据集D
D


# In[21]:

L1,suppData0=scanD(D,C1,0.5)
print(L1,suppData0)


# In[22]:

def aprioriGen(Lk,k):   #创建Ck，连接
    retList=[]
    lenLk=len(Lk)
    for i in range(lenLk):
        for j in range(i+1,lenLk):     #  比较Lk中的每一个元素与其他元素
            L1=list(Lk[i])[:k-2];L2=list(Lk[j])[:k-2]   # 若两个集合的前面k-2个元素均相等，则将这两个集合合并成一个大小为K的集合
            L1.sort();L2.sort()
            if L1==L2:
                retList.append(Lk[i]|Lk[j])
    return retList
def apriori(dataSet,minSupport=0.5):
    C1=createC1(dataSet)
    D=list(map(set,dataSet))
    L1,supportData=scanD(D,C1,minSupport)
    L=[L1]  # 列表L
    k=2
    while (len(L[k-2])>0):
        Ck=aprioriGen(L[k-2],k)
        Lk,supK=scanD(D,Ck,minSupport)
        supportData.update(supK)
        L.append(Lk)
        k+=1
    return L,supportData


# In[23]:

L,suppData=apriori(dataSet)
L


# In[24]:

print(L[0])   # 下面查看一下具体值
print(L[1])
print(L[2])
print(suppData) # suppData是一个字典，它包含项集中的支持度


# In[25]:

# 其次，如何找到关联规则,可以观察到若某条规则不满足最小可信度要求，那么该规则的所有子集也不会满足
def generateRules(L,supportData,minConf=0.7):
    bigRuleList=[]
    for i in range(1,len(L)):
        for freqSet in L[i]:
            H1=[frozenset([item]) for item in freqSet]
            if (i>1):
                rulesFromConseq(freqSet,H1,supportData,bigRuleList,minConf)
            else:
                calcConf(freqSet,H1,supportData,bigRuleList,minConf)
    return bigRuleList
def calcConf(freqSet,H,supportData,brl,minConf=0.7):      # 对规则进行评估
    prunedH=[]   
    for conseq in H:
        conf=supportData[freqSet]/supportData[freqSet-conseq]
        if conf>=minConf:
            print(freqSet-conseq,'-->',conseq,"conf:",conf)
            brl.append((freqSet-conseq,conseq,conf))
            prunedH.append(conseq)
    return prunedH
def rulesFromConseq(freqSet,H,supportData,brl,minConf=0.7):   # 用于生成候选规则集合
    m=len(H[0])
    if (len(freqSet)>(m+1)):
        Hmp1=aprioriGen(H,m+1)
        Hmp1=calcConf(freqSet,Hmp1,supportData,brl,minConf)
        if (len(Hmp1)>1):
            rulesFromConseq(freqSet,Hmp1,supportData,brl,minConf)


# In[26]:

L,suppData=apriori(dataSet,minSupport=0.5)
rules=generateRules(L,suppData,minConf=0.7)
print(rules)  # 可以观察到后两项的规则可以相互互换前件和后件


# In[27]:

rules=generateRules(L,suppData,minConf=0.5)
print(rules)   # 降低可信度阈值


# In[31]:

# 示例：发现毒蘑菇的相似特征,有时我们并不想寻找所有的频繁项集，而只对包含某个特定元素项的项集感兴趣
# 观察mushroom.dat数据集，我们只需要运行Apriori算法来寻找包含特征值为2的频繁项集
mushDatSet=[line.split() for line in open("mushroom.dat").readlines()]    # 导入数据
L1,suppData=apriori(mushDatSet,minSupport=0.3)     # 在该数据集上运行Apriori算法
for item in L[1]:
    if item.intersection('2'):   # 函数intersection是用于取交集
        print(item)
# 同时也可以对更大的项集来重复上述过程
for item in L[3]:
    if item.intersection('2'):
        print(item)
# 接下来需要观察一下这些特征


# In[ ]:




# In[ ]:



